/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_kernel.htm
 *
 * Zhiqim Kernel is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.kernel.model.seqs;

import java.util.Calendar;

import org.zhiqim.kernel.util.Arrays;
import org.zhiqim.kernel.util.Asserts;
import org.zhiqim.kernel.util.DateTimes;
import org.zhiqim.kernel.util.Longs;
import org.zhiqim.kernel.util.Strings;
import org.zhiqim.kernel.util.Validates;

/**
 * 整型序列值，默认从1从0x7FFFFFFF(最大值)，每天重新开始，并支持保存文件<br><br>
 * 1、最小值必须>=1<br>
 * 2、如果设置最大值，则最大值必须大小最小值，否则取整数最大值0x7FFFFFFF<br>
 * 3、是否自动保存
 * 
 * @version v1.0.0 @author zouzhigang 2014-2-27 新建与整理
 */
public class SequenceDateFile extends SequenceFile
{
    private static final long DAY_MS = 24 * 3600 * 1000;
    
    private long zone;
    private volatile long date;
    
    /***********************************************************************************/
    //默认自动加载
    /***********************************************************************************/
    
    /** 从1到0x7FFFFFFF，自动加载 */
    public SequenceDateFile(String filePath)
    {
        super(filePath);
    }
    
    /** 从1到len个9，自动加载 */
    public SequenceDateFile(int len, String filePath)
    {
        super(len, filePath);
    }
    
    /** 从min到max，自动加载 */
    public SequenceDateFile(long min, long max, String filePath)
    {
        super(min, max, min, filePath);
    }
    
    /** 从min到max，指定初始值，自动加载 */
    public SequenceDateFile(long min, long max, long seq, String filePath)
    {
        super(min, max, seq, filePath);
    }
    
    /***********************************************************************************/
    //设置自动/手动加载，一般用于手动加载
    /***********************************************************************************/
    
    /** 从1到0x7FFFFFFF */
    public SequenceDateFile(String filePath, boolean auto)
    {
        super(filePath, auto);
    }
    
    /** 从1到len个9 */
    public SequenceDateFile(int len, String filePath, boolean auto)
    {
        super(len, filePath, auto);
    }
    
    /** 从min到max */
    public SequenceDateFile(long min, long max, String filePath, boolean auto)
    {
        super(min, max, filePath, auto);
    }
    
    /** 从min到max，指定初始值 */
    public SequenceDateFile(long min, long max, long seq, String filePath, boolean auto)
    {
        super(min, max, seq, filePath, auto);
    }
    
    public String getDate()
    {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(date * DAY_MS);
        return DateTimes.toDateString(calendar);
    }
    
    /********************************************************************/
    //判断日期加载和保存序列号，自动标志打开时，新建即加载，每次next即保存
    /********************************************************************/
    
    @Override
    protected void init()
    {
        zone = DateTimes.toLong("1970-01-01 00:00:00");
        date = (System.currentTimeMillis() - zone) / DAY_MS;
    }
    
    @Override
    public SequenceDateFile load()
    {
        String seqs = readFile();
        if (Validates.isEmpty(seqs))
            return this;
        
        String[] daySeq = Arrays.toStringArray(seqs);
        if (daySeq.length != 2)
            return this;
        
        long day = Longs.toLong(Strings.trim(daySeq[0]), -1);
        if (day != date)
            return this;
            
        String seq = Strings.trim(daySeq[1]);
        if (!Validates.isIntegerPositive(seq))
            return this;
        
        setSequence(Longs.toLong(seq));
        return this;
    }
    
    @Override
    public void save()
    {//日期取10位最大整型，序列号取19位最大长整型，不足后补空格，保证每次写入时完整
        String day = Strings.suffixLen(date, 10, _SPACE_);
        String seq = Strings.suffixLen(sequence, 19, _SPACE_);
        writeFile(new StringBuilder(day).append(",").append(seq).toString());
    }
    
    /********************************************************************/
    //重写获取方法，按天判断，和IntSequenceDate中的方法相同
    /********************************************************************/
    
    @Override
    public long next()
    {
        if (!isValid())
        {//创建就失败，但不在构造函数中报错，而在使用时报异常
            throw Asserts.exception("创建SequenceFile失败，文件目录不存在且创建失败");
        }
        
        synchronized (this)
        {
            long day = (System.currentTimeMillis() - zone) / DAY_MS;
            if (day == date)
            {//当天的检查是否序列号回归
                chkSequence();
            }
            else
            {//跨天了重置序列号为最小值，并置日期为当前日期
                resetSequence();
                date = day;
            }
            
            long seq = sequence++;
            if (isAuto())
            {//保存下一个，返回当前
                save();
            }
            return seq;
        }
    }
}
